package main

import (
	"context"
	authpb "coolcar/auth/api/gen/v1"
	carpb "coolcar/car/api/gen/v1"
	rentalpb "coolcar/rental/api/gen/v1"
	"coolcar/shared/auth"
	"coolcar/shared/server"
	"log"
	"net/http"
	"net/textproto"

	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"github.com/namsral/flag"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/protobuf/encoding/protojson"
)

var addr = flag.String("addr", ":8080", "address to listen")
var authAddr = flag.String("auth_addr", "localhost:8081", "address for auth service")
var tripAddr = flag.String("trip_addr", "localhost:8082", "address for trip service")
var profileAddr = flag.String("profile_addr", "localhost:8082", "address for profile service")
var carAddr = flag.String("car_addr", "localhost:8084", "address for car service")

func main() {
	flag.Parse()

	logger, err := server.NewZapLogger()
	if err != nil {
		log.Fatalf("cannot create zap logger: %v", err)
	}
	ctx := context.Background()
	ctx, canel := context.WithCancel(ctx)
	defer canel()

	mux := runtime.NewServeMux(runtime.WithMarshalerOption(
		runtime.MIMEWildcard, &runtime.JSONPb{
			MarshalOptions: protojson.MarshalOptions{
				UseProtoNames:  false, // 使用proto字段名代替JSON中的骆驼式名称的字段名。
				UseEnumNumbers: true,  // 使用protoc枚举定义的值作为数字发送。
				// EmitUnpopulated: true, // 是否展示为空的字段
			},
			UnmarshalOptions: protojson.UnmarshalOptions{
				DiscardUnknown: true, // 未知字段将被忽略
			},
		},
	), runtime.WithIncomingHeaderMatcher(
		func(key string) (string, bool) {
			// 如果客户端传了一个"Grpc-Metadata-impersonate-account-id"这样的Header。
			if key == textproto.CanonicalMIMEHeaderKey(runtime.MetadataHeaderPrefix+auth.ImpersonateAccountHeader) {
				// return false 就是不把这个key对应的Header转发到gRPC的context中
				return "", false
			}
			// 然后再调用DefaultHeaderMatcher()
			return runtime.DefaultHeaderMatcher(key)
		},
	))

	serverConfig := []struct {
		name         string
		addr         string
		registerFunc func(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error)
	}{
		{
			name: "auth", addr: *authAddr,
			registerFunc: authpb.RegisterAuthServiceHandlerFromEndpoint,
		},
		{
			name: "trip", addr: *tripAddr,
			registerFunc: rentalpb.RegisterTripServiceHandlerFromEndpoint,
		},
		{
			name: "profile", addr: *profileAddr,
			registerFunc: rentalpb.RegisterProfileServiceHandlerFromEndpoint,
		},
		{
			name: "car", addr: *carAddr,
			registerFunc: carpb.RegisterCarServiceHandlerFromEndpoint,
		},
	}

	for _, s := range serverConfig {
		err := s.registerFunc(
			ctx, mux, s.addr,
			[]grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())},
		)
		if err != nil {
			logger.Sugar().Fatalf("cannot register service %s: %v", s.name, err)
		}
	}

	logger.Sugar().Infof("grpc gateway started at %s", *addr)
	logger.Sugar().Fatal(http.ListenAndServe(*addr, mux))
}
